package com.tree.leetcode.array;

import com.alibaba.fastjson.JSON;

import java.util.Arrays;

/**
 * @ClassName com.tree.leetcode.array
 * Description: 88. 合并两个有序数组
 * <p>
 * 给你两个有序整数数组 nums1 和 nums2，请你将 nums2 合并到 nums1 中，使 num1 成为一个有序数组。
 *
 *  
 *
 * 说明:
 *
 * 初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。
 * 你可以假设 nums1 有足够的空间（空间大小大于或等于 m + n）来保存 nums2 中的元素。
 *  
 *
 * 示例:
 *
 * 输入:
 * nums1 = [1,2,3,0,0,0], m = 3
 * nums2 = [2,5,6],       n = 3
 *
 * 输出: [1,2,2,3,5,6]
 *
 * 来源：力扣（LeetCode）
 * 链接：https://leetcode-cn.com/problems/merge-sorted-array
 * 著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。
 * </p>
 * @Author tree
 * @Date 2020-04-09 21:32
 * @Version 1.0
 */
public class MergeOrderedArray_88 {
    public static void main(String[] args) {
        int[] num1 = new int[]{1,2,3,0,0,0};
        int m = 3;
        int n = 3;
        int[] num2 = new int[]{2,5,6};

//        merge(num1,m,num2,n);
        merge2(num1,m,num2,n);

    }

    /**
     * 方法一：
     * 暴力排序， 直接先合并，再排序
     * 最朴素的解法就是将两个数组合并之后再排序。该算法只需要一行(Java是2行)，时间复杂度较差，
     * 为O((n + m)\log(n + m))O((n+m)log(n+m))。这是由于这种方法没有利用两个数组本身已经有序这一点。
     *
     * 作者：LeetCode
     * 链接：https://leetcode-cn.com/problems/merge-sorted-array/solution/he-bing-liang-ge-you-xu-shu-zu-by-leetcode/
     * 来源：力扣（LeetCode）
     * 著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。
     * @param nums1
     * @param m
     * @param nums2
     * @param n
     */
    public static void merge(int[] num1, int m, int[] num2, int n) {
        System.arraycopy(num2,0,num1,m,n);
        Arrays.stream(num1).forEach(value -> {
            System.out.print(value);
        });
        Arrays.sort(num1);
        System.out.println("======");
        Arrays.stream(num1).forEach(value -> {
            System.out.print(value);
        });
    }

    /**
     *
     * @param num1
     * @param m
     * @param num2
     * @param n
     */
    public static void merge2(int[] nums1, int m, int[] nums2, int n) {
        // Make a copy of nums1.
        int [] nums1_copy = new int[m];
        System.arraycopy(nums1, 0, nums1_copy, 0, m);

        // Two get pointers for nums1_copy and nums2.
        int nums1_copy_p1 = 0;
        int nums2_p2 = 0;

        // Set pointer for nums1
        int p = 0;

        // Compare elements from nums1_copy and nums2
        // and add the smallest one into nums1.
        while ((nums1_copy_p1 < m) && (nums2_p2 < n)) {
            nums1[p++] = (nums1_copy[nums1_copy_p1] < nums2[nums2_p2])
                    ? nums1_copy[nums1_copy_p1++] : nums2[nums2_p2++];
        }

        // if there are still elements to add
        if (nums1_copy_p1 < m)
            System.arraycopy(nums1_copy, nums1_copy_p1, nums1, nums1_copy_p1 + nums2_p2, m + n - nums1_copy_p1 - nums2_p2);
        if (nums2_p2 < n)
            System.arraycopy(nums2, nums2_p2, nums1, nums1_copy_p1 + nums2_p2, m + n - nums1_copy_p1 - nums2_p2);
    }

    public void merge3(int[] nums1, int m, int[] nums2, int n) {
        // two get pointers for nums1 and nums2
        int p1 = m - 1;
        int p2 = n - 1;
        // set pointer for nums1
        int p = m + n - 1;

        // while there are still elements to compare
        while ((p1 >= 0) && (p2 >= 0))
            // compare two elements from nums1 and nums2
            // and add the largest one in nums1
            nums1[p--] = (nums1[p1] < nums2[p2]) ? nums2[p2--] : nums1[p1--];

        // add missing elements from nums2
        System.arraycopy(nums2, 0, nums1, 0, p2 + 1);
    }



}
